﻿using System;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using advadev.CanOpen;


namespace advadev.CanOpen.UnitTests
{

    /// <summary>
    /// Represents the emergency object write transfer unit tests
    /// </summary>
    [TestClass]
    public class EmergencyObjectWriteTransferTest : ICanOpenObjectDictionaryContainer
    {

        #region constructor tests
        /// <summary>
        /// Constructor test
        /// </summary>
        [TestMethod]
        public void ConstructorTest()
        {
            // initialization
            byte nodeId = 103;
            CanOpenErrorCode emergencyErrorCode = new CanOpenErrorCode(0);
            CanOpenErrorRegister errorRegister = new CanOpenErrorRegister(0);
            ulong manufacturerSpecificErrorCode = 0;
            EmergencyObjectWriteTransfer testObject = null;

            // emergency error code null
            try
            {
                testObject = new EmergencyObjectWriteTransfer(null, errorRegister, manufacturerSpecificErrorCode, nodeId);
                Assert.Fail();
            }
            catch (ArgumentNullException)
            {
            }
            catch
            {
                Assert.Fail();
            }

            // error register null
            try
            {
                testObject = new EmergencyObjectWriteTransfer(emergencyErrorCode, null, manufacturerSpecificErrorCode, nodeId);
                Assert.Fail();
            }
            catch (ArgumentNullException)
            {
            }
            catch
            {
                Assert.Fail();
            }

            // node id out of range parameter
            try
            {
                testObject = new EmergencyObjectWriteTransfer(emergencyErrorCode, errorRegister, manufacturerSpecificErrorCode, 0);
                Assert.Fail();
            }
            catch (ArgumentOutOfRangeException)
            {
            }
            catch
            {
                Assert.Fail();
            }
            try
            {
                testObject = new EmergencyObjectWriteTransfer(emergencyErrorCode, errorRegister, manufacturerSpecificErrorCode, 128);
                Assert.Fail();
            }
            catch (ArgumentOutOfRangeException)
            {
            }
            catch
            {
                Assert.Fail();
            }
        }
        #endregion constructor tests


        #region producer side tests
        /// <summary>
        /// Producer side test
        /// </summary>
        [TestMethod]
        public void ProducerSideTest()
        {
            // initialization
            byte nodeId = 103;
            UInt16 cobId = 0x180;
            CanOpenErrorCode emergencyErrorCode = new CanOpenErrorCode(0);
            CanOpenErrorRegister errorRegister = new CanOpenErrorRegister(0);
            ulong manufacturerSpecificErrorCode = 0;
            EmergencyObjectWriteTransfer testObject = null;

            // test with emergency error code 10000, error register 100 and manufacturer status register 100000000000
            emergencyErrorCode.ErrorCode = 10000;
            errorRegister.ErrorRegister = 100;
            manufacturerSpecificErrorCode = 100000000000;
            testObject = new EmergencyObjectWriteTransfer(emergencyErrorCode, errorRegister, manufacturerSpecificErrorCode, nodeId);
            testObject.Start();
            Assert.AreEqual(false, testObject.TransferComplete);
            Assert.IsNull(testObject.AbortCode);
            Assert.IsNotNull(testObject.PendingSendMessages);
            Assert.AreEqual(1, testObject.PendingSendMessages.Count);
            Assert.AreEqual(0xE7, testObject.PendingSendMessages[0].CanId);
            Assert.AreEqual(0x10, testObject.PendingSendMessages[0].Byte0);
            Assert.AreEqual(0x27, testObject.PendingSendMessages[0].Byte1);
            Assert.AreEqual(0x64, testObject.PendingSendMessages[0].Byte2);
            Assert.AreEqual(0x00, testObject.PendingSendMessages[0].Byte3);
            Assert.AreEqual(0xE8, testObject.PendingSendMessages[0].Byte4);
            Assert.AreEqual(0x76, testObject.PendingSendMessages[0].Byte5);
            Assert.AreEqual(0x48, testObject.PendingSendMessages[0].Byte6);
            Assert.AreEqual(0x17, testObject.PendingSendMessages[0].Byte7);
            Assert.AreEqual((uint)8, testObject.PendingSendMessages[0].Length);
            testObject.ContinueAfterSendingMessages();
            Assert.AreEqual(true, testObject.TransferComplete);
            Assert.IsNull(testObject.AbortCode);
            Assert.IsNotNull(testObject.PendingSendMessages);
            Assert.AreEqual(0, testObject.PendingSendMessages.Count);

            // test with changed COB-ID
            emergencyErrorCode.ErrorCode = 10000;
            errorRegister.ErrorRegister = 100;
            manufacturerSpecificErrorCode = 100000000000;
            testObject = new EmergencyObjectWriteTransfer(emergencyErrorCode, errorRegister, manufacturerSpecificErrorCode, nodeId, cobId);
            testObject.Start();
            Assert.AreEqual(false, testObject.TransferComplete);
            Assert.IsNull(testObject.AbortCode);
            Assert.IsNotNull(testObject.PendingSendMessages);
            Assert.AreEqual(1, testObject.PendingSendMessages.Count);
            Assert.AreEqual(cobId + nodeId, testObject.PendingSendMessages[0].CanId);
            Assert.AreEqual(0x27, testObject.PendingSendMessages[0].Byte1);
            Assert.AreEqual(0x64, testObject.PendingSendMessages[0].Byte2);
            Assert.AreEqual(0x00, testObject.PendingSendMessages[0].Byte3);
            Assert.AreEqual(0xE8, testObject.PendingSendMessages[0].Byte4);
            Assert.AreEqual(0x76, testObject.PendingSendMessages[0].Byte5);
            Assert.AreEqual(0x48, testObject.PendingSendMessages[0].Byte6);
            Assert.AreEqual(0x17, testObject.PendingSendMessages[0].Byte7);
            Assert.AreEqual((uint)8, testObject.PendingSendMessages[0].Length);
            testObject.ContinueAfterSendingMessages();
            Assert.AreEqual(true, testObject.TransferComplete);
            Assert.IsNull(testObject.AbortCode);
            Assert.IsNotNull(testObject.PendingSendMessages);
            Assert.AreEqual(0, testObject.PendingSendMessages.Count);
        }
        #endregion producer side tests


        #region is emergency object write transfer request tests
        /// <summary>
        /// Is emergency object write transfer request test
        /// </summary>
        [TestMethod]
        public void IsEmergencyObjectWriteTransferRequestTest()
        {
            // initialization
            bool isEmergencyObjectWriteTransferRequest = false;
            UInt16 cobId = 0x181;
            CanOpenErrorCode receivedEmergencyErrorCode = new CanOpenErrorCode(0);
            CanOpenErrorRegister receivedErrorRegister = new CanOpenErrorRegister(0);
            ulong receivedManufacturerSpecificErrorCode = 0;
            EmergencyObjectReceivedEventHandler handler = new EmergencyObjectReceivedEventHandler((object sender, EmergencyObjectReceivedEventArgs args) =>
            {
                receivedEmergencyErrorCode = args.EmergencyErrorCode;
                receivedErrorRegister = args.ErrorRegister;
                receivedManufacturerSpecificErrorCode = args.ManufacturerSpecificErrorCode;
            });
            EmergencyObjectWriteTransfer testObject = null;

            // test with valid received can open message
            isEmergencyObjectWriteTransferRequest = EmergencyObjectWriteTransfer.IsEmergencyObjectWriteTransfer(new CanOpenMessage(0xE7, 0x10, 0x27, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00), out testObject, handler);
            Assert.AreEqual(true, isEmergencyObjectWriteTransferRequest);
            Assert.IsNotNull(testObject);

            // test with invalid node id
            isEmergencyObjectWriteTransferRequest = EmergencyObjectWriteTransfer.IsEmergencyObjectWriteTransfer(new CanOpenMessage(0xE7, 0x10, 0x27, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00), out testObject, cobId, handler);
            Assert.AreNotEqual(true, isEmergencyObjectWriteTransferRequest);
            Assert.IsNull(testObject);

            // test with handler is null
            isEmergencyObjectWriteTransferRequest = EmergencyObjectWriteTransfer.IsEmergencyObjectWriteTransfer(new CanOpenMessage(0xE7, 0x10, 0x27, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00), out testObject, null);
            Assert.AreEqual(true, isEmergencyObjectWriteTransferRequest);
            Assert.IsNotNull(testObject);
        }
        #endregion is emergency object write transfer request tests


        #region consumer side tests
        /// <summary>
        /// Consumer side test
        /// </summary>
        [TestMethod]
        public void ComsumerSideTest()
        {
            // initialization
            bool isEmergencyObjectWriteTransferRequest = false;
            byte nodeId = 103;
            UInt16 cobId = 0x181;
            CanOpenErrorCode receivedEmergencyErrorCode = new CanOpenErrorCode(0);
            CanOpenErrorCode emergencyErrorCode = new CanOpenErrorCode(0);
            CanOpenErrorRegister receivedErrorRegister = new CanOpenErrorRegister(0);
            CanOpenErrorRegister errorRegister = new CanOpenErrorRegister(0);
            ulong receivedManufacturerSpecificErrorCode = 0;
            ulong manufacturerSpecificErrorCode = 0;
            EmergencyObjectReceivedEventHandler handler = new EmergencyObjectReceivedEventHandler((object sender, EmergencyObjectReceivedEventArgs args) =>
            {
                receivedEmergencyErrorCode = args.EmergencyErrorCode;
                receivedErrorRegister = args.ErrorRegister;
                receivedManufacturerSpecificErrorCode = args.ManufacturerSpecificErrorCode;
            });
            EmergencyObjectWriteTransfer testObject = null;
            EmergencyObjectWriteTransfer producerTransfer = null;

            // test with emergency error code 10000, error register 100 and manufacturer status register 100000000000
            receivedEmergencyErrorCode.ErrorCode = 0;
            receivedErrorRegister.ErrorRegister = 0;
            receivedManufacturerSpecificErrorCode = 0;
            emergencyErrorCode.ErrorCode = 10000;
            errorRegister.ErrorRegister = 100;
            manufacturerSpecificErrorCode = 100000000000;
            producerTransfer = new EmergencyObjectWriteTransfer(emergencyErrorCode, errorRegister, manufacturerSpecificErrorCode, nodeId);
            producerTransfer.Start();
            isEmergencyObjectWriteTransferRequest = EmergencyObjectWriteTransfer.IsEmergencyObjectWriteTransfer(producerTransfer.PendingSendMessages[0], out testObject, handler);
            Assert.AreEqual(true, isEmergencyObjectWriteTransferRequest);
            Assert.IsNotNull(testObject);
            testObject.Start();
            Assert.AreEqual(emergencyErrorCode.ErrorCode, receivedEmergencyErrorCode.ErrorCode);
            Assert.AreEqual(errorRegister.ErrorRegister, receivedErrorRegister.ErrorRegister);
            Assert.AreEqual(manufacturerSpecificErrorCode, receivedManufacturerSpecificErrorCode);
            Assert.AreEqual(true, testObject.TransferComplete);
            Assert.IsNull(testObject.AbortCode);
            Assert.IsNotNull(testObject.PendingSendMessages);
            Assert.AreEqual(0, testObject.PendingSendMessages.Count);

            // test with changed COB-ID
            receivedEmergencyErrorCode.ErrorCode = 0;
            receivedErrorRegister.ErrorRegister = 0;
            receivedManufacturerSpecificErrorCode = 0;
            emergencyErrorCode.ErrorCode = 10000;
            errorRegister.ErrorRegister = 100;
            manufacturerSpecificErrorCode = 100000000000;
            producerTransfer = new EmergencyObjectWriteTransfer(emergencyErrorCode, errorRegister, manufacturerSpecificErrorCode, nodeId, cobId);
            producerTransfer.Start();
            isEmergencyObjectWriteTransferRequest = EmergencyObjectWriteTransfer.IsEmergencyObjectWriteTransfer(producerTransfer.PendingSendMessages[0], out testObject, cobId, handler);
            Assert.AreEqual(true, isEmergencyObjectWriteTransferRequest);
            Assert.IsNotNull(testObject);
            testObject.Start();
            Assert.AreEqual(emergencyErrorCode.ErrorCode, receivedEmergencyErrorCode.ErrorCode);
            Assert.AreEqual(errorRegister.ErrorRegister, receivedErrorRegister.ErrorRegister);
            Assert.AreEqual(manufacturerSpecificErrorCode, receivedManufacturerSpecificErrorCode);
            Assert.AreEqual(true, testObject.TransferComplete);
            Assert.IsNull(testObject.AbortCode);
            Assert.IsNotNull(testObject.PendingSendMessages);
            Assert.AreEqual(0, testObject.PendingSendMessages.Count);

            // test without handler
            receivedEmergencyErrorCode.ErrorCode = 0;
            receivedErrorRegister.ErrorRegister = 0;
            receivedManufacturerSpecificErrorCode = 0;
            emergencyErrorCode.ErrorCode = 10000;
            errorRegister.ErrorRegister = 100;
            manufacturerSpecificErrorCode = 100000000000;
            producerTransfer = new EmergencyObjectWriteTransfer(emergencyErrorCode, errorRegister, manufacturerSpecificErrorCode, nodeId);
            producerTransfer.Start();
            isEmergencyObjectWriteTransferRequest = EmergencyObjectWriteTransfer.IsEmergencyObjectWriteTransfer(producerTransfer.PendingSendMessages[0], out testObject, null);
            Assert.AreEqual(true, isEmergencyObjectWriteTransferRequest);
            Assert.IsNotNull(testObject);
            testObject.Start();
            Assert.AreEqual((ulong)0, receivedEmergencyErrorCode.ErrorCode);
            Assert.AreEqual((ulong)0, receivedErrorRegister.ErrorRegister);
            Assert.AreEqual((ulong)0, receivedManufacturerSpecificErrorCode);
            Assert.AreEqual(true, testObject.TransferComplete);
            Assert.IsNull(testObject.AbortCode);
            Assert.IsNotNull(testObject.PendingSendMessages);
            Assert.AreEqual(0, testObject.PendingSendMessages.Count);
        }
        #endregion consumer side tests


        #region ICanOpenObjectDictionaryContainer
        /// <summary>
        /// Gets the node id of the can open object dictionary container
        /// </summary>
        byte ICanOpenObjectDictionaryContainer.NodeId
        {
            get
            {
                return 103;
            }
        }

        /// <summary>
        /// Gets the can open object with the given index as can open data field
        /// object
        /// </summary>
        /// <param name="index">
        /// Index of the can open object to get
        /// </param>
        /// <returns>
        /// The can open object with the given index as data field object or
        /// null
        /// </returns>
        ICanOpenDataFieldObject ICanOpenObjectDictionaryContainer.GetCanOpenObject(UInt16 index)
        {
            return null;
        }

        /// <summary>
        /// Gets the can open object with the given index and sub index as can
        /// open value object
        /// </summary>
        /// <param name="index">
        /// Index of the can open object to get
        /// </param>
        /// <param name="subIndex">
        /// Sub index of the can open object to get
        /// </param>
        /// <returns>
        /// The can open object with the given index and sub index as value
        /// object or null
        /// </returns>
        ICanOpenValueObject ICanOpenObjectDictionaryContainer.GetCanOpenObject(UInt16 index, byte subIndex)
        {
            return null;
        }
        #endregion ICanOpenObjectDictionaryContainer

    }

}
